home *** CD-ROM | disk | FTP | other *** search
/ Aminet 33 / Aminet 33 - October 1999.iso / Aminet / util / misc / VMM_src.lha / VMM / mmu_table.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-16  |  28.6 KB  |  1,087 lines

  1. #include <exec/types.h>
  2. #include "defs.h"
  3.  
  4. static char rcsid [] = "$Id: mmu_table.c,v 3.7 95/12/16 18:36:57 Martin_Apel Exp $";
  5.  
  6. PRIVATE ULONG *MyRootTable;
  7. PRIVATE BOOL RegsWritten = FALSE;
  8. PRIVATE ULONG *MappedROM;
  9. PRIVATE struct List MemRangeList;
  10. PRIVATE BOOL MemRangeListUsed = FALSE;
  11.  
  12. #define ROMSTART 0xf80000
  13. #define ROMSIZE  0x80000
  14.  
  15. struct MemRange
  16.   {
  17.   struct MinNode mr_Node;
  18.   ULONG VirtStart,
  19.         Length,
  20.         PhysStart;
  21.   UWORD Attr;
  22.   };
  23.         
  24. /************************************************************************/
  25.  
  26. PRIVATE BOOL FindMemRange (ULONG StartAddress, ULONG *Length, 
  27.                            ULONG *PhysStart, UWORD *Attr)
  28.  
  29. {
  30. /* This tries to find a given memory range in the list. 
  31.  * It returns the attributes and the physical start address
  32.  * if an entry is found. Additionally it checks if the length
  33.  * parameter is valid. If it's not it changes it accordingly
  34.  * so this function can be called again with the next part
  35.  * of the chunk.
  36.  */
  37.  
  38. struct MemRange *range;
  39.  
  40. for (range = (struct MemRange*)MemRangeList.lh_Head; 
  41.      range->mr_Node.mln_Succ != NULL;
  42.      range = (struct MemRange*)range->mr_Node.mln_Succ)
  43.   {
  44.   if (range->VirtStart <= StartAddress && 
  45.       range->VirtStart + range->Length > StartAddress)
  46.     {
  47.     *PhysStart = range->PhysStart + (StartAddress - range->VirtStart);
  48.     *Attr = range->Attr;
  49.     if (StartAddress + *Length > range->VirtStart + range->Length)
  50.       *Length = range->VirtStart + range->Length - StartAddress;
  51.  
  52.     return (TRUE);
  53.     }
  54.   else if (range->VirtStart > StartAddress &&
  55.            range->VirtStart < StartAddress + *Length)
  56.     {
  57.     *Length = range->VirtStart - StartAddress;
  58.     return (TRUE);
  59.     }
  60.   }
  61.  
  62. return (FALSE);
  63. }
  64.  
  65. /************************************************************************/
  66.  
  67. PRIVATE void *NewPointerTable (BOOL Small)
  68.  
  69. {
  70. ULONG *PointerTable;
  71. int i;
  72.  
  73. /* Mark all table entries as invalid. Each time we come across an
  74.  * invalid table entry subsequently, a new pointer/page table is built
  75.  */
  76.  
  77. if ((PointerTable = AllocAligned (POINTERS_PER_TABLE * sizeof (ULONG),
  78.                   MEMF_PUBLIC | MEMF_REVERSE, POINTERTABALIGN, 0L)) == NULL)
  79.   return (NULL);
  80.  
  81. for (i = 0; i < POINTERS_PER_TABLE; i++)
  82.   *(PointerTable + i) = BUILD_DESCR (LOCUNUSED, PAGED_OUT, PT_TABLE);
  83.  
  84. if (!Small)
  85.   MarkPage ((ULONG)PointerTable, NONCACHEABLE);
  86.  
  87. return (PointerTable);
  88. }
  89.  
  90. /************************************************************************/
  91.  
  92. PRIVATE void *NewPageTable (BOOL Small)
  93.  
  94. {
  95. ULONG *PageTable;
  96. int i;
  97. ULONG Size,
  98.       Align;
  99.  
  100. if (Small)
  101.   {
  102.   Size = PAGES_PER_TABLE * sizeof (ULONG);
  103.   Align = PAGETABALIGN;
  104.   }
  105. else
  106.   {
  107.   Size = PAGESIZE;
  108.   Align = PAGEALIGN;
  109.   }
  110.  
  111. if ((PageTable = AllocAligned (Size, MEMF_PUBLIC | MEMF_REVERSE,
  112.                                Align, 0L)) == NULL)
  113.   return (NULL);
  114.  
  115. for (i = 0; i < Size / sizeof (ULONG); i++)
  116.   *(PageTable + i) = BUILD_DESCR (LOCUNUSED, PAGED_OUT, PT_PAGE);
  117.  
  118. if (!Small)
  119.   MarkPage ((ULONG)PageTable, NONCACHEABLE);
  120.  
  121. return (PageTable);
  122. }
  123.  
  124. /************************************************************************/
  125.  
  126. #define ALIGNED(addr,align) (((addr) & ((align) - 1)) == 0)
  127.  
  128. int MarkAddress (ULONG start, ULONG length, ULONG type, ULONG phys_addr,
  129.                   BOOL Small)
  130.  
  131. /* Marks all pages starting from "start" to "start" + "length" to
  132.  * be of type "type". Constructs intermediate pointer and page tables
  133.  * if necessary. If type represents a resident page, 'phys_addr' is the
  134.  * address, where the first page in this range maps to. 'phys_addr' is
  135.  * then incremented for each page.
  136.  * 'Small' decides, if the smallest possible MMU table is built or not.
  137.  * For memory that will be paged, 'Small' must be set to FALSE.
  138.  */
  139. {
  140. ULONG cur_addr;
  141. ULONG root_index,
  142.       table_index,
  143.       page_index;
  144. ULONG *PointerTable,
  145.       *PageTable;
  146.  
  147. PRINT_DEB ("MarkAddress from address %08lx called", start);
  148. PRINT_DEB ("                 length  %08lx", length);
  149. PRINT_DEB ("                 type %lx", type);
  150. PRINT_DEB ("Physical address %08lx", phys_addr);
  151.  
  152. if (Small && MemRangeListUsed)
  153.   {
  154.   UWORD new_type;
  155.   ULONG new_phys_addr;
  156.   ULONG new_length;
  157.   int rc;
  158.  
  159.   new_length = length;
  160.   new_phys_addr = phys_addr;
  161.   new_type = type;
  162.   if (FindMemRange (start, &new_length, &new_phys_addr, &new_type))
  163.     {
  164.     if (new_length != length)
  165.       {
  166.       rc = MarkAddress (start + new_length, length - new_length, type, 
  167.                         phys_addr + new_length, Small);
  168.       if (rc != SUCCESS)
  169.         return (rc);
  170.       }
  171.     phys_addr = new_phys_addr;
  172.     type = new_type;
  173.     length = new_length;
  174.     PRINT_DEB ("New physical address is %lx", phys_addr);
  175.     PRINT_DEB ("New length is %lx", length);
  176.     PRINT_DEB ("New attributes are %lx", (ULONG)type);
  177.     }
  178.   }
  179.  
  180. cur_addr = start;
  181. if (PAGE_INVALID_P (type))
  182.   phys_addr = 0;              /* Needed for some tests */
  183. else
  184.   phys_addr = PAGEADDR (phys_addr);
  185.  
  186. while (cur_addr < start + length)
  187.   {
  188.   /* Check for valid root entry */
  189.   root_index = ROOTINDEX (cur_addr);
  190.   if (TABLE_INVALID_P (*(RootTable + root_index)))
  191.     {
  192.     if (Small)
  193.       {
  194.       /* Check if the current range is larger than a root table range */
  195.       if (ALIGNED (cur_addr, POINTERS_PER_TABLE * PAGES_PER_TABLE * PAGESIZE) &&
  196.           ALIGNED (phys_addr, POINTERS_PER_TABLE * PAGES_PER_TABLE * PAGESIZE) &&
  197.           (cur_addr + POINTERS_PER_TABLE * PAGES_PER_TABLE * PAGESIZE <= 
  198.           start + length))
  199.         {
  200.         if (PAGE_INVALID_P (type))
  201.           {
  202.           PRINT_DEB ("Making root table entry invalid for address range"
  203.                      " starting at %08lx", cur_addr);
  204.           *(RootTable + root_index) = INVALID;
  205.           cur_addr += POINTERS_PER_TABLE * PAGES_PER_TABLE * PAGESIZE;
  206.           continue;
  207.           }
  208.         else if (ProcessorType <= PROC_68030)
  209.           {
  210.           PRINT_DEB ("Using early-termination root table entry for "
  211.                      "address range starting at %08lx", cur_addr);
  212.           *(RootTable + root_index) = phys_addr | type;
  213.           cur_addr += POINTERS_PER_TABLE * PAGES_PER_TABLE * PAGESIZE;
  214.           phys_addr += POINTERS_PER_TABLE * PAGES_PER_TABLE * PAGESIZE;
  215.           continue;
  216.           }
  217.         }
  218.       }
  219.  
  220.     if ((PointerTable = NewPointerTable (Small)) == NULL)
  221.       {
  222.       PRINT_DEB ("No mem for pointer table", 0L);
  223.       return (ERR_NOT_ENOUGH_MEM);
  224.       }
  225.     PRINT_DEB ("Allocated new pointer table for address range from %08lx", cur_addr);
  226.  
  227.     *(RootTable + root_index) = (ULONG)PointerTable | TABLE_RESIDENT;
  228.     }
  229.   else
  230.     PointerTable = (ULONG*)ALIGN_DOWN(*(RootTable + root_index),
  231.                                       POINTERTABALIGN);
  232.  
  233.   table_index = POINTERINDEX (cur_addr);
  234.  
  235.   /* Check for valid pointer entry */
  236.   if (TABLE_INVALID_P (*(PointerTable + table_index)))
  237.     {
  238.     int i;
  239.     ULONG *TableStart;
  240.  
  241.     if (Small)
  242.       {
  243.       if (ALIGNED (cur_addr, PAGES_PER_TABLE * PAGESIZE) &&
  244.           ALIGNED (phys_addr, PAGES_PER_TABLE * PAGESIZE) &&
  245.           (cur_addr + PAGES_PER_TABLE * PAGESIZE <= start + length))
  246.         {
  247.         if (PAGE_INVALID_P (type))
  248.           {
  249.           PRINT_DEB ("Making pointer table entry invalid for address range"
  250.                      " starting at %08lx", cur_addr);
  251.           *(PointerTable + table_index) = type | (PT_TABLE << 2) | INVALID;
  252.           cur_addr += PAGES_PER_TABLE * PAGESIZE;
  253.           continue;
  254.           }
  255.         else if (ProcessorType <= PROC_68030)
  256.           {
  257.           PRINT_DEB ("Using early-termination pointer table entry for "
  258.                      "address range starting at %08lx", cur_addr);
  259.           *(PointerTable + table_index) = phys_addr | type;
  260.           cur_addr += PAGES_PER_TABLE * PAGESIZE;
  261.           phys_addr += PAGES_PER_TABLE * PAGESIZE;
  262.           continue;
  263.           }
  264.         }
  265.       }
  266.  
  267.     if ((PageTable = NewPageTable (Small)) == NULL)
  268.       {
  269.       PRINT_DEB ("No mem for page table", 0L);
  270.       return (ERR_NOT_ENOUGH_MEM);
  271.       }
  272.  
  273.     PRINT_DEB ("Allocated new page table for address range from %08lx", cur_addr);
  274.  
  275.     if (!Small)
  276.       {
  277.       TableStart = PointerTable + ALIGN_DOWN (table_index,
  278.                        PAGESIZE / sizeof (ULONG) / PAGES_PER_TABLE);
  279.  
  280.       for (i = 0; i < PAGESIZE / sizeof (ULONG) / PAGES_PER_TABLE; i++)
  281.         {
  282.         *(TableStart + i) = (ULONG)(PageTable + i * PAGES_PER_TABLE) | TABLE_RESIDENT;
  283.         }
  284.       }
  285.     else
  286.       *(PointerTable + table_index) = (ULONG)PageTable | TABLE_RESIDENT;
  287.     }
  288.  
  289.   PageTable = (ULONG*) ALIGN_DOWN(*(PointerTable + table_index),
  290.                                   PAGETABALIGN);
  291.  
  292.   page_index = PAGEINDEX (cur_addr);
  293.   *(PageTable + page_index) = type;
  294.   cur_addr += PAGESIZE;
  295.  
  296.   if (PAGE_RESIDENT_P (type))
  297.     {
  298.     *(PageTable + page_index) |= phys_addr;
  299.     phys_addr += PAGESIZE;
  300.     }
  301.   else
  302.     *(PageTable + page_index) |= (PT_PAGE << 2) | INVALID;
  303.   }
  304. return (SUCCESS);
  305. }
  306.  
  307. /************************************************************************/
  308.  
  309. #define TT40_ENABLED (1L<<15)
  310. #define TC40_ENABLED (1L<<15)
  311. #define TC40_PAGESIZE (1L<<14)
  312. #define TC40_PAGE_4K 0
  313. #define TC40_PAGE_8K (1L<<14)
  314.  
  315. #define TT30_ENABLED (1L<<15)
  316. #define TC30_ENABLED (1L<<15)
  317. #define TC30_PAGE_4K 0
  318. #define TC30_PAGE_8K (1L<<14)
  319.  
  320. /************************************************************************/
  321.  
  322. PRIVATE BOOL TTHit (ULONG address)
  323.  
  324. {
  325. /* Determines if a given address hits into a transparent translation
  326.  * register. 
  327.  */
  328.  
  329. return ((BOOL)((*GenDescr) (address) & USED));   /* U bit used as TT hit indicator */
  330. }
  331.  
  332. /************************************************************************/
  333.  
  334. PRIVATE int BuildMemRangeList (BPTR MMUConfigFile)
  335.  
  336. {
  337. char line [80],
  338.      buffer [20];
  339. struct MemRange *range;
  340.  
  341. PRINT_DEB ("Reading MMU configuration from VMM_MMU.config", 0L);
  342.  
  343. MemRangeListUsed = TRUE;
  344. while (FGets (MMUConfigFile, line, 79) != NULL)
  345.   {
  346.   ULONG log_start,
  347.         phys_start,
  348.         length,
  349.         attr;
  350.  
  351.   StrToHex (line, &log_start);
  352.  
  353.   GetNthString (line, buffer, 2);
  354.   StrToHex (buffer,  &phys_start);
  355.  
  356.   GetNthString (line, buffer, 3);
  357.   StrToHex (buffer, &length);
  358.  
  359.   GetNthString (line, buffer, 4);
  360.   StrToHex (buffer, &attr);
  361.  
  362.   if ((range = DoOrigAllocMem (sizeof (struct MemRange), MEMF_PUBLIC)) == NULL)
  363.     return (ERR_NOT_ENOUGH_MEM);
  364.   AddTail (&MemRangeList, (struct Node*)range);
  365.  
  366.   if ((log_start == 0) && (phys_start == 0) && (length == 0))
  367.     {
  368.     range->VirtStart = 0L;
  369.     range->Length    = 0x80000000;
  370.     range->PhysStart = 0L;
  371.     range->Attr      = attr;
  372.  
  373.     if ((range = DoOrigAllocMem (sizeof (struct MemRange), MEMF_PUBLIC)) == NULL)
  374.       return (ERR_NOT_ENOUGH_MEM);
  375.     range->VirtStart = 0x80000000;
  376.     range->Length    = 0x80000000;
  377.     range->PhysStart = 0x80000000;
  378.     range->Attr      = attr;
  379.     AddTail (&MemRangeList, (struct Node*)range);
  380.     continue;
  381.  
  382.     }
  383.  
  384.   /* Do just a small consistency check here */
  385. #ifdef PAGE4K
  386.   if (length == 0 || ((length % PAGESIZE) != 0))
  387. #else
  388.   if (length == 0 || ((length % (PAGESIZE / 2)) != 0))
  389. #endif
  390.     {
  391.     Close (MMUConfigFile);
  392.     return (ERR_CORRUPT_CFG_FILE);
  393.     }
  394.  
  395.   range->VirtStart = log_start;
  396.   range->Length    = length;
  397.   range->PhysStart = phys_start;
  398.   range->Attr      = attr;
  399.   }
  400.  
  401. return (SUCCESS);
  402. }
  403.  
  404. /************************************************************************/
  405.  
  406. int SetupMMUTable (void)
  407.  
  408. {
  409. struct MemHeader *mem;
  410. struct ConfigDev *cd=NULL;
  411. ULONG PhysROMStart;
  412. BOOL OutOfMem = FALSE;
  413. BPTR MMUConfigFile;
  414. struct MMUState40 MMUState40;
  415. struct MMUState30 MMUState30;
  416. ULONG *VectorTable;
  417.  
  418. NewList (&MemRangeList);
  419.  
  420. if (IsA3000)
  421.   {
  422.   UBYTE *ForceReset = (UBYTE*)0xde0002;
  423.  
  424.   *ForceReset |= 0x80;
  425.   }
  426.  
  427. if ((MMUConfigFile = Open (MMUCFG_FILENAME, MODE_OLDFILE)) != NULL)
  428.   {
  429.   int rc;
  430.  
  431.   rc = BuildMemRangeList (MMUConfigFile);
  432.   Close (MMUConfigFile);
  433.   if (rc != SUCCESS)
  434.     return (rc);
  435.   }
  436.  
  437. switch (ProcessorType)
  438.   {
  439.   case PROC_68040:
  440.   case PROC_68060:
  441.     ReadMMUState40 (&MMUState40);
  442.  
  443.     RootTable = (ULONG*)MMUState40.URP;
  444.  
  445.     /* Check if Zorro III autoconfiguration space is mapped by the 
  446.      * transparent translation registers. If not there is no need
  447.      * to set up our own MMU table unless the pagesize is different.
  448.      */
  449.  
  450.     #if PAGESIZE==4096
  451.       if (((MMUState40.TC & (TC40_ENABLED | TC40_PAGESIZE)) == (TC40_ENABLED | TC40_PAGE_4K)) && 
  452.           !TTHit (EZ3_CONFIGAREA) && 
  453.           (MMUConfigFile == NULL))
  454.            return (SUCCESS);
  455.     #else
  456.  
  457.       if (((MMUState40.TC & (TC40_ENABLED | TC40_PAGESIZE)) == (TC40_ENABLED | TC40_PAGE_8K)) && 
  458.          !TTHit (EZ3_CONFIGAREA) &&
  459.           (MMUConfigFile == NULL))
  460.            return (SUCCESS);
  461.  
  462.     #endif
  463.  
  464.     break;
  465.  
  466.   case PROC_68030:
  467.   case PROC_68851:
  468.     if (ProcessorType == PROC_68030)
  469.       ReadMMUState30 (&MMUState30);
  470.     else
  471.       ReadMMUState851 (&MMUState30);
  472.  
  473.     RootTable = (ULONG*)MMUState30.CRP_Lo;
  474.  
  475.     if ((MMUState30.TC == (MAKE_MASK(TC_E, TC_E, 1L ) |
  476.                            MAKE_MASK( TC_SRE, TC_SRE, 0L ) |
  477.                            MAKE_MASK( TC_FCL, TC_FCL, 0L ) |
  478.                            MAKE_MASK( TC_PS_START, TC_PS_END, PAGE_BITS ) |
  479.                            MAKE_MASK( TC_IS_START, TC_IS_END, 0L ) |
  480.                            MAKE_MASK( TC_TIA_START, TC_TIA_END, LEVEL_A_BITS ) |
  481.                            MAKE_MASK( TC_TIB_START, TC_TIB_END, LEVEL_B_BITS ) |
  482.                            MAKE_MASK( TC_TIC_START, TC_TIC_END, LEVEL_C_BITS ) |
  483.                            MAKE_MASK( TC_TID_START, TC_TID_END, 0L ))) &&
  484.         !TTHit (EZ3_CONFIGAREA) &&
  485.         (MMUConfigFile == NULL))
  486.          return (SUCCESS);
  487.     break;
  488.  
  489. #ifdef DEBUG
  490.   default:
  491.     PRINT_DEB ("SetupMMUTable: Unknown processor type", 0L);
  492.     ColdReboot ();
  493. #endif
  494.   }
  495.  
  496. /* Allocate memory for the root table */
  497.  
  498. if ((MyRootTable = NewPointerTable (TRUE)) == NULL)
  499.   {
  500.   PRINT_DEB ("SetupMMUTable: No mem for root table", 0L);
  501.   return (ERR_NOT_ENOUGH_MEM);
  502.   }
  503.  
  504. RootTable = MyRootTable;
  505.  
  506. PRINT_DEB ("Initialized root table at %08lx", (ULONG) MyRootTable);
  507.  
  508. /* The following code is taken from the Enforcer documentation */
  509.  
  510. OutOfMem |= MarkAddress (0L, PAGESIZE, NONCACHEABLE | PAGE_RESIDENT, 0L, TRUE) != SUCCESS;
  511.  
  512. /*
  513.  * Map in the free memory
  514.  */
  515. Forbid();
  516. mem=(struct MemHeader *)SysBase->MemList.lh_Head;
  517. while (mem->mh_Node.ln_Succ)
  518.   {
  519.   ULONG CM;
  520.  
  521.   CM = (*GenDescr) ((ULONG)mem->mh_Lower) & CM_MASK;
  522.   OutOfMem |= MarkAddress (PAGEADDR ((ULONG)mem->mh_Lower),
  523.               (ULONG)mem->mh_Upper - PAGEADDR((ULONG)mem->mh_Lower),
  524.               CM | PAGE_RESIDENT,
  525.               PAGEADDR ((ULONG)mem->mh_Lower), TRUE) != SUCCESS;
  526.  
  527.   mem=(struct MemHeader *)(mem->mh_Node.ln_Succ);
  528.   }
  529. Permit();
  530.  
  531. PRINT_DEB ("RAM entered into MMU table", 0L);
  532.  
  533. /*
  534.  * Now for the control areas...
  535.  */
  536. OutOfMem |= MarkAddress (0x00BC0000, 0x00040000, PAGE_RESIDENT | NONCACHEABLE,
  537.                          0x00BC0000, TRUE) != SUCCESS;
  538. OutOfMem |= MarkAddress (0x00D80000, 0x00080000, PAGE_RESIDENT | NONCACHEABLE,
  539.                          0x00D80000, TRUE) != SUCCESS;
  540. OutOfMem |= MarkAddress (0x00E80000, 0x00080000, PAGE_RESIDENT | NONCACHEABLE,
  541.                          0x00E80000, TRUE) != SUCCESS;
  542.  
  543. PRINT_DEB ("Control areas entered into MMU table", 0L);
  544.  
  545. /*
  546.  * Map in the autoconfig boards
  547.  */
  548.  
  549. while (cd=FindConfigDev(cd,-1L,-1L))
  550. {
  551.   /* Skip memory boards... */
  552.   if (!(cd->cd_Rom.er_Type & ERTF_MEMLIST))
  553.     {
  554.     ULONG CM;
  555.  
  556.     PRINT_DEB ("Adding Autoconfig device at %08lx", (ULONG)cd->cd_BoardAddr);
  557.     PRINT_DEB ("                  size      %08lx", cd->cd_BoardSize);
  558.  
  559.     CM = (*GenDescr) ((ULONG)(cd->cd_BoardAddr)) & CM_MASK;
  560.  
  561.     OutOfMem |= MarkAddress((ULONG)(cd->cd_BoardAddr), cd->cd_BoardSize,
  562.                             PAGE_RESIDENT | CM,
  563.                             (ULONG)(cd->cd_BoardAddr), TRUE) != SUCCESS;
  564.     }
  565. }
  566.  
  567. PRINT_DEB ("AutoConfig boards entered into MMU table", 0L);
  568.  
  569. /*
  570.  * and the ROM...
  571.  */
  572.  
  573. PhysROMStart = PAGEADDR ((*GenDescr) (ROMSTART));
  574. PRINT_DEB ("Physical kickstart address = %08lx", PhysROMStart);
  575.  
  576. OutOfMem |= MarkAddress(ROMSTART, ROMSIZE,
  577.                         PAGE_RESIDENT | CACHEABLE | WRITEPROTECT,
  578.                         PhysROMStart, TRUE) != SUCCESS;
  579.  
  580. PRINT_DEB ("ROM entered into MMU table", 0L);
  581.  
  582. /*
  583.  * If the credit card resource, make the addresses valid...
  584.  */
  585. if (OpenResource("card.resource"))
  586.   {
  587.   OutOfMem |= MarkAddress(0x00600000,0x00440000,
  588.                           PAGE_RESIDENT | NONCACHEABLE, 0x00600000, TRUE) != SUCCESS;
  589.   PRINT_DEB ("Entered card.resource into MMU table", 0L);
  590.   }
  591.  
  592. /*
  593.  * Check for ReKick/ZKick/KickIt
  594.  */
  595. if ((((ULONG)(SysBase->LibNode.lib_Node.ln_Name)) >> 16) == 0x20)
  596.   {
  597.   OutOfMem |= MarkAddress(0x00200000, 0x00080000,
  598.                           PAGE_RESIDENT | CACHEABLE | WRITEPROTECT,
  599.                           0x00200000, TRUE) != SUCCESS;
  600.   }
  601.  
  602. /* OK, now the MMU table is set up like the one constructed by Enforcer.
  603.  * Enable the MMU
  604.  */
  605.  
  606. if (OutOfMem)
  607.   {
  608.   PRINT_DEB ("Not enough memory for pagetables", 0L);
  609.   return (ERR_NOT_ENOUGH_MEM);
  610.   }
  611.  
  612. PRINT_DEB ("MMU table ready for usage", 0L);
  613.  
  614. CacheClearU ();
  615. Disable ();
  616. VectorTable = (ULONG*)ReadVBR ();
  617. PRINT_DEB ("VBR = %lx", (ULONG)VectorTable);
  618. OrigDynMMUTrap = (void (*) ()) *(VectorTable + 2);
  619.  
  620. switch (ProcessorType)
  621.   {
  622.   case PROC_68040:
  623.   case PROC_68060:
  624.     #if PAGESIZE==4096
  625.       MMUState40.TC = TC40_ENABLED | TC40_PAGE_4K;
  626.     #else
  627.       MMUState40.TC = TC40_ENABLED | TC40_PAGE_8K;
  628.     #endif
  629.  
  630.     MMUState40.URP = (ULONG)MyRootTable;
  631.     MMUState40.SRP = (ULONG)MyRootTable;
  632.     MMUState40.ITT0 = 
  633.     MMUState40.ITT1 = 
  634.     MMUState40.DTT0 = 
  635.     MMUState40.DTT1 = 0L;
  636.  
  637.     SaveMMUState40 ();
  638.     PRINT_DEB ("MMU state saved", 0L);
  639.     SetMMUState40 (&MMUState40);
  640.     PRINT_DEB ("MMU state set", 0L);
  641.  
  642.     if (MemRangeListUsed)    
  643.       {
  644.       if (ProcessorType == PROC_68040)
  645.         {
  646.         PRINT_DEB ("Installing dynamic MMU trap for 68040", 0L);
  647.         *(VectorTable + 2) = (ULONG)&DynMMUTrap40;
  648.         PRINT_DEB ("Trap-vector set", 0L);
  649.         }
  650.       else
  651.         {
  652.         PRINT_DEB ("Installing dynamic MMU trap for 68060", 0L);
  653.         *(VectorTable + 2) = (ULONG)&DynMMUTrap60;
  654.         PRINT_DEB ("Trap-vector set", 0L);
  655.         }
  656.       }
  657.     break;
  658.  
  659.   case PROC_68030:
  660.   case PROC_68851:
  661.     if (MemRangeListUsed)    
  662.       {
  663.       PRINT_DEB ("Installing dynamic MMU trap for 68030/68851", 0L);
  664.       *(VectorTable + 2) = (ULONG)&DynMMUTrap30;
  665.       }
  666.  
  667.     MMUState30.TC = MAKE_MASK(TC_E, TC_E, 1L ) |
  668.                     MAKE_MASK( TC_SRE, TC_SRE, 0L ) |
  669.                     MAKE_MASK( TC_FCL, TC_FCL, 0L ) |
  670.                     MAKE_MASK( TC_PS_START, TC_PS_END, PAGE_BITS ) |
  671.                     MAKE_MASK( TC_IS_START, TC_IS_END, 0L ) |
  672.                     MAKE_MASK( TC_TIA_START, TC_TIA_END, LEVEL_A_BITS ) |
  673.                     MAKE_MASK( TC_TIB_START, TC_TIB_END, LEVEL_B_BITS ) |
  674.                     MAKE_MASK( TC_TIC_START, TC_TIC_END, LEVEL_C_BITS ) |
  675.                     MAKE_MASK( TC_TID_START, TC_TID_END, 0L );
  676.  
  677.     PRINT_DEB("TC30=%08lx", MMUState30.TC);
  678.  
  679.     MMUState30.CRP_Hi = MAKE_MASK( RP_LU-32, RP_LU-32, 1L ) |
  680.                         MAKE_MASK( RP_LIMIT_START-32, RP_LIMIT_END-32, 0L ) |
  681.                         MAKE_MASK( RP_DT_START-32, RP_DT_END-32, DT_VALID4BYTE );
  682.     MMUState30.CRP_Lo = MAKE_MASK( RP_TA_START, RP_TA_END, ((ULONG)MyRootTable)
  683.                                    >> TABLE_ADDRESS_SHIFT);
  684.  
  685.     PRINT_DEB("CRP30.HI=%08lx", MMUState30.CRP_Hi);
  686.     PRINT_DEB("CRP30.LO=%08lx", MMUState30.CRP_Lo);
  687.  
  688.     MMUState30.SRP_Hi = MMUState30.CRP_Hi;
  689.     MMUState30.SRP_Lo = MMUState30.CRP_Lo;
  690.     /* TT registers are ignored for the 68851 */
  691.     MMUState30.TT0 = 
  692.     MMUState30.TT1 = 0;
  693.  
  694.     if (ProcessorType == PROC_68030)
  695.       {
  696.       SaveMMUState30 ();
  697.       SetMMUState30(&MMUState30);
  698.       }
  699.     else
  700.       {
  701.       SaveMMUState851 ();
  702.       SetMMUState851(&MMUState30);
  703.       }
  704.     break;
  705.  
  706. #ifdef DEBUG
  707.   default:
  708.     PRINT_DEB ("SetupMMUTable: Unknown processor type 2", 0L);
  709.     ColdReboot ();
  710. #endif
  711.   }
  712.  
  713. CacheClearU ();
  714. Enable ();
  715. RegsWritten = TRUE;
  716.  
  717. PRINT_DEB ("MMU table fully set up", 0L);
  718. return (SUCCESS);
  719. }
  720.  
  721. /************************************************************************/
  722.  
  723. BOOL KillPageTable (ULONG *pt, BOOL FreePages)
  724.  
  725. {
  726. int i;
  727. BOOL PagesLocked = FALSE;
  728.  
  729. for (i = 0; i < PAGES_PER_TABLE; i++)
  730.   {
  731.   if (PAGE_RESIDENT_P (*(pt + i)))
  732.     {
  733.     if (LOCKED_P (*(pt + i)))
  734.       PagesLocked = TRUE;
  735.     else if (FreePages)
  736.       FreeMem ((APTR)PAGEADDR (*(pt + i)), PAGESIZE);
  737.     }
  738.   }
  739.  
  740. if (PagesLocked)
  741.   return (FALSE);
  742.  
  743. FreeMem (pt, PAGES_PER_TABLE * sizeof (ULONG));
  744. return (TRUE);
  745. }
  746.  
  747. /************************************************************************/
  748.  
  749. BOOL KillPointerTable (ULONG *pt, BOOL FreePages)
  750.  
  751. {
  752. int i;
  753. ULONG *address;
  754. BOOL do_kill = TRUE;
  755.  
  756. for (i = 0; i < POINTERS_PER_TABLE; i++)
  757.   {
  758.   if (TABLE_RESIDENT_P (*(pt + i)))
  759.     {
  760.     address = (ULONG*) ALIGN_DOWN (*(pt + i), PAGETABALIGN);
  761.     do_kill = KillPageTable (address, FreePages) && do_kill;
  762.     }
  763.   }
  764.  
  765. if (do_kill)
  766.   {
  767.   PRINT_DEB ("Freeing pointer table", 0L);
  768.   FreeMem (pt, POINTERS_PER_TABLE * sizeof (ULONG));
  769.   }
  770. return (do_kill);
  771. }
  772.  
  773. /************************************************************************/
  774.  
  775. void KillMMUTable (void)
  776.  
  777. {
  778. int i;
  779. ULONG *address;
  780. struct MemRange *range;
  781.  
  782. if (RegsWritten)
  783.   {
  784.   Disable ();
  785.  
  786.   if (IsA3000)
  787.     {
  788.     UBYTE *ForceReset = (UBYTE*)0xde0002;
  789.  
  790.     *ForceReset &= ~0x80;
  791.     }
  792.  
  793.   switch (ProcessorType)
  794.     {
  795.     case PROC_68060:
  796.     case PROC_68040: RestoreMMUState40 ();
  797.                      break;
  798.     case PROC_68030: RestoreMMUState30 ();
  799.                      break;
  800.     case PROC_68851: RestoreMMUState851 ();
  801.                      break;
  802. #ifdef DEBUG
  803.     default:
  804.       PRINT_DEB ("KillMMUTable: Unknown processor type", 0L);
  805.       ColdReboot ();
  806. #endif
  807.     }
  808.  
  809.   Enable ();
  810.   }
  811.  
  812. if (MyRootTable != NULL)
  813.   {
  814.   for (i = 0; i < POINTERS_PER_TABLE; i++)
  815.     {
  816.     if (TABLE_RESIDENT_P (*(MyRootTable + i)))
  817.       {
  818.       address = (ULONG*) ALIGN_DOWN (*(MyRootTable + i), POINTERTABALIGN);
  819.       KillPointerTable (address, FALSE);
  820.       }
  821.     }
  822.   FreeMem (MyRootTable, POINTERS_PER_TABLE * sizeof (ULONG));
  823.   }
  824.  
  825. if (MemRangeListUsed)
  826.   {
  827.   ULONG *VectorTable;
  828.  
  829.   while ((range = (struct MemRange*)RemHead (&MemRangeList)) != NULL)
  830.     FreeMem (range, sizeof (struct MemRange));
  831.  
  832.   Forbid ();
  833.   PRINT_DEB ("Removing dynamic MMU trap", 0L);
  834.   VectorTable = (ULONG*)ReadVBR ();
  835.   *(VectorTable + 2) = (ULONG) OrigDynMMUTrap;
  836.   CacheClearU ();
  837.   Permit ();
  838.   }
  839. }
  840.  
  841. /************************************************************************/
  842.  
  843. void AllowZorroIICaching (BOOL Allowed)
  844.  
  845. {
  846. struct MemHeader *mem;
  847. int rc;
  848.  
  849. if (MemRangeListUsed)
  850.   return;
  851.  
  852. Forbid();
  853. mem=(struct MemHeader *)SysBase->MemList.lh_Head;
  854. while (mem->mh_Node.ln_Succ)
  855.   {
  856.   if ((ULONG)mem->mh_Lower < 0x01000000 && !(mem->mh_Attributes & MEMF_CHIP))
  857.     {
  858.     if (Allowed)
  859.       {
  860.       PRINT_DEB ("Marking chunk as cacheable", 0L);
  861.       if ((rc = MarkAddress(PAGEADDR ((ULONG)mem->mh_Lower),
  862.                    (ULONG)mem->mh_Upper-PAGEADDR((ULONG)mem->mh_Lower),
  863.                    CACHEABLE | PAGE_RESIDENT, 
  864.                    PAGEADDR((ULONG)mem->mh_Lower), TRUE)) != SUCCESS)
  865.         RunTimeError (rc);
  866.       }
  867.     else
  868.       {
  869.       PRINT_DEB ("Marking chunk as non-cacheable", 0L);
  870.       if ((rc = MarkAddress(PAGEADDR((ULONG)mem->mh_Lower),
  871.                    (ULONG)mem->mh_Upper-PAGEADDR((ULONG)mem->mh_Lower),
  872.                    NONCACHEABLE | PAGE_RESIDENT, 
  873.                    PAGEADDR((ULONG)mem->mh_Lower), TRUE)) != SUCCESS)
  874.         RunTimeError (rc);
  875.       }
  876.     }
  877.   mem=(struct MemHeader *)(mem->mh_Node.ln_Succ);
  878.   }
  879. Permit();
  880.  
  881. (*PFlushA) ();
  882. }
  883.  
  884. /************************************************************************/
  885.  
  886. int AllocAddressRange (void)
  887.  
  888. {
  889. /* Get NUM_PTR_TABLES * 32 MB of address space starting on a 32 MB boundary.
  890.  * Additionally this checks if some badly designed processor card already
  891.  * used the address range without notifying the autoconfig system about
  892.  * it.
  893.  */
  894. ULONG start_slot;
  895.  
  896. if ((start_slot = (ULONG)AllocExpansionMem (NUM_PTR_TABLES * 512L, 0L)) == 0)
  897.   return (ERR_NO_ADDR_SPACE);
  898.  
  899. VirtAddrStart = EC_MEMADDR (start_slot);
  900. VirtAddrEnd   = EC_MEMADDR (start_slot) + NUM_PTR_TABLES * 0x02000000;
  901. PRINT_DEB ("AllocAddressRange: VirtAddrStart = %08lx", VirtAddrStart);
  902.  
  903. return (SUCCESS);
  904. }
  905.  
  906. /************************************************************************/
  907.  
  908. int SwitchFastROM (BOOL On)
  909.  
  910. {
  911. /* Turning FastROM on:
  912.  * Copies the ROM memory to FAST memory and adjusts the memory maps
  913.  * such that the FAST image is used instead. The $f80000 range as well
  914.  * as the mapped image is FAST mem is set to write-protected.
  915.  * It is safe to call this if it wsa already turned on.
  916.  * Returns TRUE if it was possible to set up everything as needed.
  917.  * Turning FastROM off:
  918.  * If it was turned on previously, it is turned off. Otherwise
  919.  * nothing will happen.
  920.  */
  921.  
  922. if (MemRangeListUsed)
  923.   return (SUCCESS);
  924.  
  925. if (On)
  926.   {
  927.   if (PAGEADDR ((*GenDescr) (ROMSTART)) != ROMSTART)
  928.     {
  929.     PRINT_DEB ("SwitchFastROM (On): FastROM was already on", 0L);
  930.     return (TRUE);         /* Already mapped */
  931.     }
  932.  
  933.   /* The alignment to ROMSIZE is necessary because of problems with early-termination
  934.    * descriptor on the 68030. If the alignment is not kept, the page tables will
  935.    * be trashed.
  936.    */
  937.   if ((MappedROM = AllocAligned (ROMSIZE, MEMF_PUBLIC | MEMF_FAST, ROMSIZE, 0)) == NULL)
  938.     {
  939.     PRINT_DEB ("SwitchFastROM: No Mem for Fast ROM", 0L);
  940.     return (ERR_NOT_ENOUGH_MEM);
  941.     }
  942.  
  943.   CopyMemQuick ((ULONG*)ROMSTART, MappedROM, ROMSIZE);
  944.   CacheClearU ();
  945.  
  946.   Forbid ();
  947.   /* Mark copied are under original address as write-protected */
  948.   if (MarkAddress ((ULONG)MappedROM, ROMSIZE, PAGE_RESIDENT | CACHEABLE | WRITEPROTECT,
  949.                    (ULONG)MappedROM, TRUE) != SUCCESS)
  950.     {
  951.     Permit ();
  952.     return (ERR_INTERNAL);
  953.     }
  954.  
  955.   if (MarkAddress (ROMSTART, ROMSIZE, PAGE_RESIDENT | CACHEABLE | WRITEPROTECT, 
  956.                    (ULONG)MappedROM, TRUE) != SUCCESS)
  957.     {
  958.     FreeMem (MappedROM, ROMSIZE);
  959.     MappedROM = NULL;
  960.     Permit ();
  961.     return (ERR_NOT_ENOUGH_MEM);
  962.     }
  963.  
  964.   Permit ();
  965.   PRINT_DEB ("Successfully turned on FastROM", 0L);
  966.   }
  967. else
  968.   {
  969.   if (MappedROM == NULL)
  970.     {
  971.     PRINT_DEB ("SwitchFastROM (Off): FastROM was already off", 0L);
  972.     return (SUCCESS);
  973.     }
  974.  
  975.   Forbid ();
  976.   if (MarkAddress (ROMSTART, ROMSIZE, PAGE_RESIDENT | CACHEABLE | WRITEPROTECT,
  977.                    ROMSTART, TRUE) != SUCCESS)
  978.     {
  979.     Permit ();
  980.     return (ERR_INTERNAL);
  981.     }
  982.  
  983.   if (MarkAddress ((ULONG)MappedROM, ROMSIZE, PAGE_RESIDENT | CACHEABLE, 
  984.                    (ULONG)MappedROM, TRUE) != SUCCESS)
  985.     {
  986.     return (ERR_INTERNAL);
  987.     }
  988.  
  989.   Permit ();
  990.   FreeMem (MappedROM, ROMSIZE);
  991.   MappedROM = NULL;
  992.   PRINT_DEB ("Successfully turned off FastROM", 0L);
  993.   }
  994.  
  995. (*PFlushA) ();
  996. return (SUCCESS);
  997. }
  998.  
  999. /************************************************************************/
  1000.  
  1001. void InstallMapping (ULONG Address)
  1002.  
  1003. /* This function gets called from a special traphandler whenever an address
  1004.  * is used for which no valid mapping exists, but which is neither in pageable
  1005.  * memory. 'InstallMapping' installs a mapping for the pagetable in which this
  1006.  * address lies. It should not be called if no MMU config file exists.
  1007.  */
  1008.  
  1009. {
  1010. int rc;
  1011.  
  1012. PRINT_DEB ("InstallMapping with address %lx called", Address);
  1013.  
  1014. Address = ALIGN_DOWN (Address, PAGES_PER_TABLE * PAGESIZE);
  1015. rc = MarkAddress (Address, PAGES_PER_TABLE * PAGESIZE, 
  1016.                   NONCACHEABLE | PAGE_RESIDENT, Address, TRUE);
  1017. CacheClearU ();
  1018. (*PFlushA) ();
  1019. if (rc != SUCCESS)
  1020.   {
  1021.   RunTimeError (ERR_DYN_MAP_FAILED);
  1022.   Wait (0L);
  1023.   }
  1024. PRINT_DEB ("Successfully installed mapping for address range starting at %lx", Address);
  1025. }
  1026.  
  1027. /************************************************************************/
  1028.  
  1029. void MarkPage (ULONG addr, ULONG CacheMode)
  1030.  
  1031. /* Marks a page used for holding page or pointer tables as noncacheable
  1032.  * or cacheable.
  1033.  * It searches the current MMU table for the right entry and changes
  1034.  * the cache mode settings.
  1035.  */
  1036.  
  1037. {
  1038. ULONG root_index,
  1039.       table_index,
  1040.       page_index;
  1041. ULONG *PointerTable,
  1042.       *PageTable;
  1043. ULONG entry;
  1044.  
  1045. PRINT_DEB ("MarkPage (%lx) called", addr);
  1046.  
  1047. if (CacheMode == NONCACHEABLE)
  1048.   (*CPushP) (addr);
  1049.  
  1050. #ifdef DEBUG
  1051. if (ProcessorType < PROC_68040)
  1052.   PRINT_DEB ("MarkPage: Called for 68030 or worse", 0L);
  1053. #endif
  1054.  
  1055. root_index = ROOTINDEX (addr);
  1056. #ifdef DEBUG
  1057. if (TABLE_INVALID_P (*(RootTable + root_index)))
  1058.   {
  1059.   PRINT_DEB ("MarkPage: Invalid root entry = %08lx", *(RootTable + root_index));
  1060.   }
  1061. #endif
  1062.  
  1063. PointerTable = (ULONG*)ALIGN_DOWN(*(RootTable + root_index),
  1064.                                   POINTERTABALIGN);
  1065.  
  1066. table_index = POINTERINDEX (addr);
  1067. #ifdef DEBUG
  1068. if (TABLE_INVALID_P (*(PointerTable + table_index)))
  1069.   PRINT_DEB ("MarkPage: Invalid pointer entry", 0L);
  1070. #endif
  1071.  
  1072. PageTable = (ULONG*) ALIGN_DOWN(*(PointerTable + table_index),
  1073.                                 PAGETABALIGN);
  1074.  
  1075. page_index = PAGEINDEX (addr);
  1076. #ifdef DEBUG
  1077. if (PAGE_INVALID_P (*(PageTable + page_index)))
  1078.   PRINT_DEB ("MarkPage: Invalid page entry", 0L);
  1079. #endif
  1080.  
  1081. entry = *(PageTable + page_index) & ~CM_MASK;          /* remove old caching bits */
  1082. PRINT_DEB ("Setting page table entry to %08lx", entry | CacheMode);
  1083. *(PageTable + page_index) = entry | CacheMode;
  1084. (*CPushL) ((ULONG)(PageTable + page_index));
  1085. (*PFlushP) (addr);
  1086. }
  1087.